package com.linser.gistools.common.datastore.model;
import javafx.concurrent.Task;
import org.geotools.data.*;
import org.geotools.data.collection.ListFeatureCollection;
import org.geotools.data.simple.SimpleFeatureCollection;
import org.geotools.data.simple.SimpleFeatureIterator;
import org.geotools.data.simple.SimpleFeatureSource;
import org.geotools.feature.DefaultFeatureCollection;
import org.geotools.feature.NameImpl;
import org.geotools.jdbc.JDBCDataStore;
import org.geotools.referencing.CRS;
import org.locationtech.jts.geom.Geometry;
import org.opengis.feature.simple.SimpleFeature;
import org.opengis.feature.simple.SimpleFeatureType;
import org.opengis.feature.type.AttributeDescriptor;
import org.opengis.filter.Filter;
import org.opengis.referencing.FactoryException;
import org.opengis.referencing.crs.CoordinateReferenceSystem;

import java.io.IOException;
import java.sql.*;
import java.util.*;

/**
 * @author: linser
 * @Desc: 数据源 后面加Model是为了防止命名冲突
 * @create: 2024-01-28 20:22
 **/
public class BaseDataStoreModel implements BaseDataStoreInterface {
    //唯一值
    private String uuid;

    //数据库版本号
    private String version;
    @Override
    public String getVersion() {
        return version;
    }

    private void setVersion() throws SQLException {
        JDBCDataStore store = (JDBCDataStore)this.getDataStore();
        Connection interconnection = store.getDataSource().getConnection();
        DatabaseMetaData metaData = interconnection.getMetaData();
        this.version = metaData.getDatabaseProductVersion();
    }

    private DbInfo dbInfo;

    //数据源中的表列表
    protected List<DataTableModel> dbTableLst;

    //数据源连接对象
    protected Map<String, Object> localConnectionDataMap = null;

    //数据源
    protected DataStore dataStore;

    public BaseDataStoreModel() {
        this.setUuid();
    }
    public BaseDataStoreModel(DbInfo dbInfo) {
        this.dbInfo = dbInfo;
        this.setUuid();
    }
    public BaseDataStoreModel(DbInfo dbInfo, Map<String, Object> localConnectionDataMap) {
        this.dbInfo = dbInfo;
        this.localConnectionDataMap = localConnectionDataMap;
        this.setUuid();
    }
    @Override
    public String getUuid() {
        return uuid;
    }

    @Override
    public void setUuid() {
        this.uuid =  UUID.randomUUID().toString();
    }
    @Override
    public void setUuid(String uuid) {
        if(uuid == null){
            this.uuid =  UUID.randomUUID().toString();
        }else {
            this.uuid = uuid;
        }
    }

    @Override
    public DbInfo getDbInfo() {
        return dbInfo;
    }

    @Override
    public void setDbInfo(DbInfo dbInfo) {
        this.dbInfo = dbInfo;
    }

    @Override
    public List<DataTableModel> getDbTableLst() {
        if (this.dbTableLst == null) {
            synchronized(this) {
                if (this.dbTableLst == null) {
                    this.dbTableLst = new ArrayList();
                    try {
                        DataStore dataStore = this.getDataStore();
                        if (dataStore != null) {
                            //此方法不兼容mysql8.x 总是会查询当前链接下所有库的表 不能直接使用
                            String[] allowTableNames = dataStore.getTypeNames();

                            JDBCDataStore store = (JDBCDataStore)dataStore;
                            Connection interconnection = store.getDataSource().getConnection();
                            // 获取数据库元数据
                            DatabaseMetaData metaData = interconnection.getMetaData();
                            // 获取表信息的结果集
                            ResultSet resultSet = metaData.getTables(this.getDbInfo().getDatabase(), null, null, new String[]{"TABLE"});
                            // 遍历结果集，获取表名
                            while (resultSet.next()) {
                                String tableName = resultSet.getString("TABLE_NAME");
                                boolean containsTarget = Arrays.asList(allowTableNames).contains(tableName);
                                if(containsTarget){
                                    // 获取表的特征源
                                    SimpleFeatureType simpleFeatureType = dataStore.getSchema(tableName);
                                    FeatureSource<SimpleFeatureType, SimpleFeature> featureSource = dataStore.getFeatureSource(new NameImpl(tableName));
                                    DataTableModel dataTable = new DataTableModel(this);
                                    // 判断是否为空间表
                                    if (featureSource != null && featureSource.getSchema().getGeometryDescriptor() != null) {
                                        dataTable.setSpatial(true);
                                    }
                                    dataTable.setTableName(tableName);
                                    this.dbTableLst.add(dataTable);
                                }
                            }
                        }
                    } catch (IOException var9) {
                        var9.printStackTrace();
                    } catch (SQLException e) {
                        throw new RuntimeException(e);
                    }
                }
            }
        }

        return this.dbTableLst;
    }


    public SimpleFeatureCollection getFeatureCollection(String tablename) throws IOException {
        FeatureSource<SimpleFeatureType, SimpleFeature> featureSource = this.dataStore.getFeatureSource(tablename);
        SimpleFeatureCollection features = (SimpleFeatureCollection) featureSource.getFeatures();
        return features;
    }

    @Override
    public void setDbTableLst(List<DataTableModel> dbTableLst) {
        this.dbTableLst = dbTableLst;
    }

    @Override
    public Map<String, Object> getLocalConnectionDataMap() {
        return this.localConnectionDataMap;
    }

    @Override
    public void setLocalConnectionDataMap(Map<String, Object> localConnectionDataMap) {
        this.localConnectionDataMap = localConnectionDataMap;
    }

    @Override
    public DataStore getDataStore() {
        if (this.dataStore == null) {
            synchronized(this) {
                if (this.dataStore == null) {
                    try {
                        this.dataStore = DataStoreFinder.getDataStore(this.getLocalConnectionDataMap());
                        // 获取数据源版本信息
                        this.setVersion();
                        //this.setVersion(info.get)
                    }catch (SQLException | IOException e) {
                        throw new RuntimeException(e);
                    }
                }
            }
        }

        return this.dataStore;
    }

    @Override
    public void setDataStore(DataStore dataStore) {
        this.dataStore = dataStore;
    }

    @Override
    public List getChildsLst() {
        return this.getDbTableLst();
    }

    @Override
    public List refreshChildsLst() {
        this.setDbTableLst((List)null);
        return this.getDbTableLst();
    }

    @Override
    public String getUrlStr() {
        return "";
    }

    @Override
    public List<FieldModel> getTableField(String tableName) {
        List<FieldModel> list = new ArrayList();
        DataStore dataStore = this.getDataStore();

        try {
            SimpleFeatureSource featureSource = dataStore.getFeatureSource(tableName);
            List<AttributeDescriptor> attributeDescriptors = ((SimpleFeatureType)featureSource.getSchema()).getAttributeDescriptors();
            Iterator var6 = attributeDescriptors.iterator();

            while(var6.hasNext()) {
                AttributeDescriptor attributeDescriptor = (AttributeDescriptor)var6.next();
                FieldModel fieldModel = FieldModel.getFromAttributeDescriptoe(attributeDescriptor);
                list.add(fieldModel);
            }
        } catch (IOException var9) {
            var9.printStackTrace();
        }

        return list;
    }


    @Override
    public void update() {
        this.setDbTableLst((List)null);
        this.setDataStore((DataStore)null);
        this.setLocalConnectionDataMap((Map)null);
    }

    @Override
    public Integer queryFeatureCount(String featureName, Filter fiter) {
        Integer countall = 0;
        try {
            SimpleFeatureSource simpleFeatureSource = this.getDataStore().getFeatureSource(featureName);
            Query attributeQuerry = new Query();
            if (fiter != null) {
                attributeQuerry.setFilter(fiter);
            }

            countall = simpleFeatureSource.getCount(attributeQuerry);
        } catch (IOException var6) {
            var6.printStackTrace();
        }

        return countall;
    }

    @Override
    public SimpleFeatureCollection queryFeatureByQuery(String featureName, Query query) {
        DefaultFeatureCollection defaultFeatureCollection = new DefaultFeatureCollection();

        try {
            query.setTypeName(featureName);
            FeatureReader featureReader = this.getDataStore().getFeatureReader(query, Transaction.AUTO_COMMIT);

            while(featureReader.hasNext()) {
                SimpleFeature feature = (SimpleFeature)featureReader.next();
                defaultFeatureCollection.add(feature);
            }
        } catch (IOException var6) {
            var6.printStackTrace();
        }

        return defaultFeatureCollection;
    }

    @Override
    public boolean equalsWithMap(Map params) {
        return false;
    }

    public void createTable(SimpleFeatureType schema){
        try {
//            JDBCDataStore targetstore = (JDBCDataStore) this.getDataStore();
//            MySQLDialectBasic dialect = new MySQLDialectBasic(targetstore);
//            dialect.setStorageEngine("InnoDB");
//            targetstore.setSQLDialect(dialect);
            //创建数据表
            this.dataStore.createSchema(schema);

        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

    @Override
    public boolean appendData(SimpleFeatureCollection sourceFeatureCollection, DataTableModel targetTable) {
        boolean res = false;
        if (this.getDataStore() != null) {
            DataStore targetStore = this.getDataStore();

//            try {
//                if (targetStore.getSchema(targetTable.getTableName()) == null) {
//                    //this.getContext().getSindaPrinStream().writErrorStr("错误：表格不存在于目标数据库");
//                    return res;
//                }
//
//                res = this.appendFeatures(sourceFeatureCollection, targetTable.getTableName());
//            } catch (IOException var7) {
//                var7.printStackTrace();
//            }
        }

        return res;
    }

    @Override
    public Task<Void> appendFeatures(SimpleFeatureCollection source, SimpleFeatureType targetFeatureType) {
        return new Task<Void>() {

            @Override
            protected Void call() throws Exception {
                DataStore targetstore = getDataStore();
                int count = 0;
                int allCount = source.size();
                Integer attributeCount = targetFeatureType.getAttributeCount();
                List<AttributeDescriptor> filedsList = targetFeatureType.getAttributeDescriptors();
                if (targetstore != null) {
                    FeatureWriter<SimpleFeatureType, SimpleFeature> writer = null;
                    Transaction transaction = new DefaultTransaction("create");
                    createTable(targetFeatureType);
                    try {
                        writer = targetstore.getFeatureWriterAppend(String.valueOf(targetFeatureType.getName()), transaction);
                    } catch (IOException var25) {
                        var25.printStackTrace();
                    }

                    SimpleFeatureIterator it = source.features();

                    while(it.hasNext()) {
                        SimpleFeature feature = it.next();
                        try {
                            SimpleFeature targetfeature = writer.next();
                            for(int i = 0; i < attributeCount; ++i) {
                                AttributeDescriptor attributeDescriptor = filedsList.get(i);
                                if (attributeDescriptor.getType().getClass().getSimpleName().equalsIgnoreCase("GeometryTypeImpl")) {
                                    Geometry orginGeo = (Geometry)feature.getAttribute(attributeDescriptor.getLocalName());
                                    targetfeature.setAttribute(attributeDescriptor.getLocalName(), orginGeo);
                                } else {
                                    targetfeature.setAttribute(attributeDescriptor.getLocalName(), feature.getAttribute(attributeDescriptor.getLocalName()));
                                }
                            }

                            writer.write();
                            count ++ ;
                            if(allCount > 5000){
                                if (count++ % 1000 == 0) {
                                    updateProgress((float) count, (float) allCount);  // 更新进度条的进度
                                }
                            }else {
                                updateProgress((float) count, (float) allCount);  // 更新进度条的进度
                            }
                        } catch (IOException var26) {
                            var26.printStackTrace();
                        }
                    }
                    try {
                        transaction.commit();
                        writer.close();
                    } catch (IOException var24) {
                        var24.printStackTrace();
                    }
                }
                return null;
            }
        };
    }

    @Override
    public boolean delTable(String tableName) {
        boolean res = false;
        DataStore dataStore = this.getDataStore();

        try {
            dataStore.removeSchema(tableName);
            res = true;
            List<DataTableModel> dataTables = this.getDbTableLst();
            DataTableModel removeTable = null;
            Iterator var6 = dataTables.iterator();

            while(var6.hasNext()) {
                DataTableModel sindaDataTable = (DataTableModel)var6.next();
                if (sindaDataTable.getTableName().toUpperCase().equalsIgnoreCase(tableName.toUpperCase())) {
                    removeTable = sindaDataTable;
                    break;
                }
            }

            if (removeTable != null) {
                this.getDbTableLst().remove(removeTable);
            }

            System.out.println("成功：删除表" + tableName + "成功");
        } catch (IOException var8) {
            System.out.println("操作失败：删除表" + tableName + "失败！" + var8.getLocalizedMessage());
            var8.printStackTrace();
        }

        return res;
    }


    @Override
    public Integer getTableEpsgCode(String tableName) {
        DataStore dataStore = this.getDataStore();

        try {
            SimpleFeatureType featureType = dataStore.getSchema(tableName);
            CoordinateReferenceSystem coordinateReferenceSystem = featureType.getCoordinateReferenceSystem();
            return CRS.lookupEpsgCode(coordinateReferenceSystem, true);
        } catch (IOException var5) {
            var5.printStackTrace();
        } catch (FactoryException var6) {
            var6.printStackTrace();
        } catch (NullPointerException var7) {
            var7.printStackTrace();
        }

        return 0;
    }

    @Override
    public boolean testDbStoreSql(String sql) {
        return false;
    }


    @Override
    public SimpleFeatureCollection getfeaturesByTableName(String tableName) {
        if (this.getDataStore() == null) {
            return null;
        } else {
            try {
                SimpleFeatureSource featureSource = this.getDataStore().getFeatureSource(tableName);
                SimpleFeatureCollection featureCollection = featureSource.getFeatures();
                return featureCollection;
            } catch (IOException var5) {
                var5.printStackTrace();
                return null;
                //this.getContext().getSindaPrinStream().writErrorStr(this.getName() + "数据获取失败！" + var5.getMessage());
            }
        }
    }

}
